package org.hive.testserver.domain.model;

import java.util.Collections;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.hive.testserver.domain.model.schedule.ScheduleReason;
import org.hive.testserver.domain.util.Clock;

public abstract class BaseWork implements Work {

	protected String uuid;
	protected long started;
	protected long duration = 0;
	protected Slave assignedSlave;
	protected String result = "";
	protected SortedMap<String, String> resultContext = new TreeMap<String,String>();
	protected boolean isFinished = false;
	protected Clock clock;
	private String scheduledReason;

	public static final String STARTED_ACCESSOR = "started";
	
	public BaseWork(Slave slave, ScheduleReason scheduledReason, Clock clock) {
		super();
		this.uuid = UUID.randomUUID().toString();
		this.started = clock.currentTimeMillis();
		this.assignedSlave = slave;
		this.clock = clock;
		this.scheduledReason = scheduledReason.toString();
	}

	public String getName() {
		return uuid;
	}
	
	public void finished(Slave slave, String result, Map<String, String> workContext) {
		verifyUnfinished();
		verifyOwnerSlave(slave);
		isFinished = true;
		this.result = result;
		resultContext.putAll(workContext);
		duration = clock.currentTimeMillis() - started;
	}

	private void verifyUnfinished() {
		if (isFinished) {
			throw new IllegalStateException("Work already finished: "+getId()+ " with: "+result());
		}
	}

	private void verifyOwnerSlave(Slave slave) {
		if (!assignedSlave.equals(slave)) {
			throw new IllegalStateException("Work can only be finished by assigned slave: "+assignedSlave.getName()+ ", not: "+slave.getName());
		}
	}

	public String result() {
		return result;
	}
	
	public SortedMap<String,String> resultContext() {
		return Collections.unmodifiableSortedMap(resultContext);
	}
	
	public boolean isFinished() {
		return isFinished;
	}

	public Slave assignedSlave() {
		return assignedSlave;
	}
	
	public long started() {
		return started;
	}
	
	public long duration() {
		return duration;
	}
	
	public String getTestName() {
		return StringUtils.EMPTY;
	}
	
	public String scheduledReason() {
		return scheduledReason;
	}
}
